﻿using System;
using System.Collections.ObjectModel;
using System.Data;
using System.Linq;
using BB.Processes.Services.Logging;
using BB.Processes.Services.Rss;

namespace BB.Processes.Services.Processes
{
    public class Apostas
    {
        private static Models.ApostasBalasContext db = new Models.ApostasBalasContext();
        private static Log4NetLogger logger = new Log4NetLogger();

        public const string Win = "W";
        public const string Draw = "D";
        public const string Lose = "L";
        public const string RssUrl = "http://feeds.feedburner.com/futebol365/resultados";

        public enum Score
        {
            Win = 3,
            Draw = 1,
            Lose = 0
        }

        public static void ExecuteRss()
        {
            try
            {
                RssManager reader = new RssManager();
                Collection<Rss.Rss.Items> list;
                reader.Url = RssUrl;
                reader.GetFeed();
                list = reader.RssItems;
                for (int i = 0; i < list.Count; i++)
                {
                    //add the title, link and public date
                    //of each feed item to the ListBox
                    //var liga = list[i].Title.Substring(0, list[i].Title.IndexOf(":"));
                    var iliga = list[i].Title.Contains("Liga Zon Sagres");
                    if (iliga)
                    {
                        var result = list[i].Title
                            .Substring(list[i].Title.IndexOf(":") + 1)
                            .Trim()
                            .Split('-');

                        var homeTeam = result[0].Substring(0, result[0].Length - 1).Trim();
                        var awayTeam = result[1].Substring(1).Trim();

                        var homeScore = result[0].Substring(result[0].Length - 1).Trim();
                        var awayScore = result[1].Substring(0, 1).Trim();

                        var jogo = db.Jogoes.Where(j => j.Fulfilled == false && j.Date < DateTime.Now
                                                        && j.HomeTeam == homeTeam && j.AwayTeam == awayTeam).SingleOrDefault();
                        if (jogo != null)
                        {
                            jogo.HomeScore = Int32.Parse(homeScore);
                            jogo.AwayScore = Int32.Parse(awayScore);
                            db.Entry(jogo).State = EntityState.Modified;
                            db.SaveChanges();
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                logger.Error(ex);
            }
        }

        public static void ExecuteApostas()
        {
            try
            {
                var apostas = db.Apostas
                    .Where(a => a.Jogo.Fulfilled == true || a.Jogo.Date < DateTime.Now)
                    .ToList();

                foreach (var aposta in apostas)
                {
                    string result = Lose;
                    int score = (int)Score.Lose;
                    //Resultado Exacto
                    if (aposta.Jogo.HomeScore == aposta.HomeScore
                        & aposta.Jogo.AwayScore == aposta.AwayScore)
                    {
                        result = Win;
                        score = (int)Score.Win;
                    }
                    //Vitoria jogo em casa
                    else if (aposta.Jogo.HomeScore > aposta.Jogo.AwayScore
                        & aposta.HomeScore > aposta.AwayScore)
                    {
                        result = Draw;
                        score = (int)Score.Draw;
                    }
                    //Vitoria jogo fora
                    else if (aposta.Jogo.HomeScore < aposta.Jogo.AwayScore
                        & aposta.HomeScore < aposta.AwayScore)
                    {
                        result = Draw;
                        score = (int)Score.Draw;
                    }
                    //Empate
                    else if (aposta.Jogo.HomeScore == aposta.Jogo.AwayScore
                        & aposta.HomeScore == aposta.AwayScore)
                    {
                        result = Draw;
                        score = (int)Score.Draw;
                    }

                    aposta.Result = result;
                    aposta.Score = score;
                    db.Entry(aposta).State = EntityState.Modified;
                    db.SaveChanges();
                }
            }
            catch (Exception ex)
            {
                logger.Error(ex);
            }
        }

        public static void ExecuteJogos()
        {
            try
            {
                var jogos = db.Jogoes
                    .Where(j => j.Fulfilled == false)
                    .ToList();

                foreach (var jogo in jogos)
                {
                    if (jogo.Date < DateTime.Now)
                    {
                        jogo.Fulfilled = true;
                        db.Entry(jogo).State = EntityState.Modified;
                        db.SaveChanges();
                    }
                }
            }
            catch (Exception ex)
            {
                logger.Error(ex);
            }
        }

        public static void ExecuteJornadas()
        {
            try
            {
                var jornadas = db.Jornadas
                    .Where(j => j.Fulfilled == false)
                    .ToList();

                foreach (var jornada in jornadas)
                {
                    var Complete = false;

                    var jogos = db.Jogoes
                        .Where(j => j.JornadaId == jornada.Id)
                        .OrderByDescending(j => j.Date).FirstOrDefault();

                    if (jogos == null)
                        continue;

                    if (jogos.Date < DateTime.Now)
                    {
                        Complete = true;
                        ExecuteClassificacao(jornada.Id, jornada.CompeticaoId);
                    }

                    jornada.Fulfilled = Complete;
                    db.Entry(jornada).State = EntityState.Modified;
                    db.SaveChanges();
                }
            }
            catch (Exception ex)
            {
                logger.Error(ex);
            }
        }

        private static void ExecuteClassificacao(int jornadaid, int? competicaoid)
        {
            try
            {
                var users = db.UserProfiles.ToList();
                foreach (var user in users)
                {
                    var exists = db.Classificacaos
                           .Where(c => c.UserId == user.UserId
                               && c.CompeticaoId == competicaoid && c.JornadaId == jornadaid)
                           .Any();

                    var existsOld = db.Classificacaos
                          .Where(c => c.UserId == user.UserId
                              && c.CompeticaoId == competicaoid && c.JornadaId == (jornadaid - 1))
                          .Any();

                    var classificacaoNew = new Models.Classificacao();

                    if (!exists && !existsOld)
                    {
                        var iFlag = db.Apostas
                       .Where(a => a.Jogo.JornadaId == jornadaid && a.Jogo.CompeticaoId == competicaoid
                           && a.UserId == user.UserId).Any();

                        if (!iFlag)
                            continue;

                        var score = db.Apostas
                       .Where(a => a.Jogo.JornadaId == jornadaid && a.Jogo.CompeticaoId == competicaoid
                           && a.UserId == user.UserId)
                       .Sum(a => a.Score);

                        var wins = db.Apostas
                       .Where(a => a.Jogo.JornadaId == jornadaid && a.Jogo.CompeticaoId == competicaoid
                           && a.UserId == user.UserId && a.Result == Win).Count();

                        var draws = db.Apostas
                       .Where(a => a.Jogo.JornadaId == jornadaid && a.Jogo.CompeticaoId == competicaoid
                           && a.UserId == user.UserId && a.Result == Draw).Count();

                        var losses = db.Apostas
                       .Where(a => a.Jogo.JornadaId == jornadaid && a.Jogo.CompeticaoId == competicaoid
                           && a.UserId == user.UserId && a.Result == Lose).Count();


                        classificacaoNew.UserId = user.UserId;
                        classificacaoNew.CompeticaoId = (int)competicaoid;
                        classificacaoNew.JornadaId = jornadaid;
                        classificacaoNew.D = draws;
                        classificacaoNew.L = losses;
                        classificacaoNew.W = wins;
                        classificacaoNew.GF = wins;
                        classificacaoNew.GA = losses;
                        classificacaoNew.Score = score;
                        db.Classificacaos.Add(classificacaoNew);
                        db.SaveChanges();
                        continue;
                    }

                    var lastClass = db.Classificacaos
                        .Where(c => c.UserId == user.UserId && c.CompeticaoId == competicaoid)
                        .OrderByDescending(c => c.JornadaId)
                        .FirstOrDefault();

                    var iFlagLast = db.Apostas
                      .Where(a => a.Jogo.JornadaId == jornadaid && a.Jogo.CompeticaoId == competicaoid
                          && a.UserId == user.UserId).Any();

                    int lastscore = 0;
                    if (iFlagLast)
                    {
                        lastscore = db.Apostas
                        .Where(a => a.Jogo.JornadaId == jornadaid && a.Jogo.CompeticaoId == competicaoid
                            && a.UserId == user.UserId)
                        .Sum(a => a.Score);
                    }

                    var lastwins = db.Apostas
                   .Where(a => a.Jogo.JornadaId == jornadaid && a.Jogo.CompeticaoId == competicaoid
                       && a.UserId == user.UserId && a.Result == Win).Count();

                    var lastdraws = db.Apostas
                   .Where(a => a.Jogo.JornadaId == jornadaid && a.Jogo.CompeticaoId == competicaoid
                       && a.UserId == user.UserId && a.Result == Draw).Count();

                    var lastlosses = db.Apostas
                   .Where(a => a.Jogo.JornadaId == jornadaid && a.Jogo.CompeticaoId == competicaoid
                       && a.UserId == user.UserId && a.Result == Lose).Count();

                    classificacaoNew.UserId = user.UserId;
                    classificacaoNew.CompeticaoId = (int)competicaoid;
                    classificacaoNew.JornadaId = jornadaid;
                    classificacaoNew.D = lastClass.D + lastdraws;
                    classificacaoNew.GA = lastClass.GA + lastlosses;
                    classificacaoNew.GF = lastClass.GF + lastwins;
                    classificacaoNew.L = lastClass.L + lastlosses;
                    classificacaoNew.Score = lastClass.Score + lastscore;
                    classificacaoNew.W = lastClass.W + lastwins;

                    db.Classificacaos.Add(classificacaoNew);
                    db.SaveChanges();
                }
            }
            catch (Exception ex)
            {
                logger.Error(ex);
            }
        }

        public static void ExecutarNotificacao()
        {
            try
            {
                var noticia = new Models.Noticia();
                noticia.Date = DateTime.Now;
                noticia.Message = "Classificacao Actualizada!";
                db.Noticias.Add(noticia);
                db.SaveChanges();

                //Enviar email
            }
            catch (Exception ex)
            {
                logger.Error(ex);
            }
        }
    }
}
